查看原文
其他

[笨叔点滴15]ARMv8里异常处理哪些蛇神牛鬼 2

小笨叔 奔跑吧Linux社区 2019-04-24

 一个行者问老和尚:“您得道前,做什么?”老和尚:“砍柴担水做饭。”行者问:“那得道后呢?”老和尚:“砍柴担水做饭。”行者又问:“那何谓得道?”老和尚:“得道前,砍柴时惦记着挑水,挑水时惦记着做饭;得道后,砍柴即砍柴,担水即担水,做饭即做饭。”



很多时候平凡的日子不平凡。


上一次我们讲到ARM v8的异常向量表(上一期节目点击这里)。我们以data abort这个异常为例子。假设data abort发生在EL1这个异常级别里。它会从异常向量表里跳转到el1_sync这个汇编函数里。



第270行的kernel_entry是一个汇编的宏,用来保存发生异常现场,把相关CPU寄存器保存到EL1的栈里,这里和ARM32的代码类似,会有一个栈框,这栈框的大小是S_FRAME_SIZE,该栈框大小是一个软件定义的,而非硬件定义,也就是说你可以实现一个和Linux实现不一样的栈框。


接下来读取esr_el1j寄存器的值。ESR_EL1寄存器全称exception syndrome register,可以参考ARM v8手册第D10.2.36章内容。这个寄存器有点类似ARM v7中的DFSR寄存器。这个寄存器的具体定义在D10.2.39章。


在这个寄存器里,EC域保存了异常的类型(exception class)。对于current EL的data abort,可以看手册的定义,当EC== 100101的时候就是表示当前EL发生了data abort异常。



这个值和代码里273行的ESR_ELx_EC_DABT_CUR的定义是吻合的,它定义在arch/arm64/include/asm/esr.h文件中。


所以根据274行代码会跳转到el1_da汇编函数里。这个函数也是在entry.S文件里。


首先去读取far_el1寄存器。这个寄存器是在第D10.2.40章里。这寄存器保存了导致异常发生的虚拟地址,那我们操作系统就可以读取这个寄存器来继续后续的异常处理,它很类似ARM V7中的DFAR寄存器。


第二步是开启中断。

第三步跳转到do_mem_abort函数里。



这个函数有三个参数,其中第一个和第二参数需要注意,第一个参数是异常发生时候那个错误的虚拟地址,即读取的FAR_EL1寄存器,第二参数是ESR_EL1寄存器。不过第二个参数有不少花头。


ESR_EL1寄存器的bit  26~31比特位是Exception class,bit 0 ~24是ISS域,它会根据 exception class的不同 而有不同的解读,也就是说,Exception class不同,ISS域的编码是 不一样的。对应Data abort这个类型来说,ISS的编码是在ARM v8手册的2460页里。见下面这个图。



其中bit 0~5是指示具体发生了那种类型的data abort。我们以level 3的页表转换错误为例(translation fault level 3),我们看到在DFSC域里,它是000111,也就是7号。


我们看一下Linux内核代码,在arch/arm64/mm/fault.c文件中有一个fault_info[ ]的数组,我们看看7号是对应是神马?


我们惊奇发现fault_info[ ]数组里7号就是level 3的translation fault,对应的处理函数是do_page_fault函数,见第386行代码。大家可以从0开始来数这个数组。


我们通过两期的笨叔点滴来go through了一遍ARM V8上发生异常的台前幕后,希望对大家有所帮助。更多精彩内容敬请关注笨叔的第二季《奔跑吧Linux内核》配套视频。




第二季来啦



大家期待的第二季视频来了,我们这次是进程管理、锁机制以及中断管理三合一,加量不加价旗舰篇还是原价1199,现在特价999。


初级篇: 笨叔和大家彻底理清进程管理、锁机制以及中断管理相关的概念。比如说:

  1. 进程的生命周期

  2. 进程控制块

  3. 进程调度的本质

  4. CFS调度器

  5. 进程切换是怎么玩

  6. SMP负载均衡

  7. 大小核调度是怎么回事

  8. 为啥需要中断

  9. 中断发生了ARMv7和ARMv8处理器做了啥

  10. 中断底层汇编处理

  11. 中断上下半部

  12. 如何写好一个中断处理函数

  13. 软中断是怎么回事

  14. tasklet和workqueue怎么玩

  15. 什么是中断上下文

  16. 为啥需要锁

  17. 什么是原子操作

  18. ARMv7和ARMv8处理器怎么进行原子操作的

  19. 内存屏障是什么

  20. spinlock怎么用

  21. 信号量和mutex该选谁

  22. RCU怎么用

  23. 为啥这里要添加一个锁

  24. ...


旗舰篇包含初级篇内容,还包含如下特色:

  1. 额外增加核心代码的导读,真正做到自主可控。

  2. 综合创新实验,笨叔带领大家在树莓派上玩一个小OS。

  3. 面试宝典,那些年我们被虐过的面试题目。


 


现在第二季旗舰篇和初级篇正在火热接收预定,预计8月28号开始陆续发货。点击“阅读原文”进入订阅页面。


订阅旗舰篇优惠活动:

  1. 已经订阅第一季旗舰篇的小伙伴,再订阅第二季旗舰篇可以返回100元现金。同时一起订阅第一季+第二季旗舰篇的小伙伴也是同样返回100元现金。(100元现金是微信返回)

  2. 订阅了第一季+第二季旗舰篇的小伙伴,参加转发笨叔点滴活动可以获得《奔跑吧Linux内核》入门篇签名新书,新书预计2018年双十一或者双十二出版。




[往期精彩]

第二季旗舰篇终于来了,进程管理、中断管理和锁机制三合一

[旗舰篇] 第一季旗舰篇资料汇总

不能不会的VIM+GIT

《奔跑吧Linux內核》繁體版預覽

[笨叔点滴14] ARMv8里异常处理哪些蛇神牛鬼 1

[笨叔点滴13]哪些异常处理的事儿

[笨叔点滴12]面试必考:如果在中断处理函数里发生了缺页中断会怎样?为什么?

[笨叔点滴11] malloc惹的祸

[笨叔点滴10] 中断到“底”来了吗?

[笨叔点滴9] GNU GCC扩展2

[笨叔点滴8] GNU C语言的扩展

[笨叔点滴7] 再也回不去的C语言

[笨叔点滴6] 叔,这个git咋玩啊?

[笨叔点滴5] git rebase和git merge究竟有啥区别?

[笨叔点滴4]“栈”谁便宜了2

[笨叔点滴3] “栈”谁便宜了?

[笨叔点滴2] 为啥子ARM32体系结构中每个处理模式都有一个单独的栈?

[笨叔点滴1] 为什么do_page_fault函数里代码需要判断用户态还是内核态?

LinuxCon 2018北京游记(1)

LinuxCon2018北京笨叔笨游记 2

《奔跑吧linux内核》配套资源迁移到码云上

考点来了:4月18号视频更新

代码导读之如何使用qemu来单步调试head.S

代码导读之内存管理初始化 - 启动汇编

视频更新:内存管理代码框架导读

DMA那些事儿

私密VIP群答疑

高级运维必杀技:如何图形化单步调试RHEL/Centos 7里的内核?

首发:Meltdown漏洞分析与实践

[奔跑吧Linux内核] 故乡

致敬Beyond


    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存